home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 24
/
Aminet 24 (1998)(GTI - Schatztruhe)[!][Apr 1998].iso
/
Aminet
/
comm
/
mail
/
Mutt089src.lha
/
Mutt-0.89i-AMIGA
/
src
/
mh.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-01-28
|
12KB
|
531 lines
/*
* Copyright (C) 1996-8 Michael R. Elkins <me@cs.hmc.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
* This file contains routines specific to MH and ``maildir'' style mailboxes
*/
#include "mutt.h"
#include "mx.h"
#include "mailbox.h"
#include "parse.h"
#include <sys/stat.h>
#include <dirent.h>
#include <limits.h>
#include <unistd.h>
#include <ctype.h>
#include <errno.h>
#include <string.h>
void mh_parse_message (CONTEXT *ctx,
const char *subdir,
const char *fname,
int *count,
int isOld)
{
char path[_POSIX_PATH_MAX];
char *p;
FILE *f;
HEADER *h;
struct stat st;
if (subdir)
snprintf (path, sizeof (path), "%s/%s/%s", ctx->path, subdir, fname);
else
snprintf (path, sizeof (path), "%s/%s", ctx->path, fname);
if ((f = fopen (path, "r")) != NULL)
{
(*count)++;
if (!ctx->quiet && ReadInc && ((*count % ReadInc) == 0 || *count == 1))
mutt_message ("Reading %s... %d", ctx->path, *count);
if (ctx->msgcount == ctx->hdrmax)
mx_alloc_memory (ctx);
h = ctx->hdrs[ctx->msgcount] = mutt_new_header ();
if (subdir)
{
snprintf (path, sizeof (path), "%s/%s", subdir, fname);
h->path = safe_strdup (path);
}
else
h->path = safe_strdup (fname);
h->env = mutt_read_rfc822_header (f, h);
fstat (fileno (f), &st);
fclose (f);
if (!h->received)
h->received = h->date_sent;
if (h->content->length <= 0)
h->content->length = st.st_size - h->content->offset;
/* index doesn't have a whole lot of meaning for MH and maildir mailboxes,
* but this is used to find the current message after a resort in
* the `index' event loop.
*/
h->index = ctx->msgcount;
if (ctx->magic == M_MAILDIR)
{
/* maildir stores its flags in the filename, so ignore the flags in
* the header of the message
*/
h->old = isOld;
#ifdef AMIGA
/* ':' is volume separator and cannot be used in filenames */
/* we're using ';' to be consistent with qmail port */
if ((p = strchr (h->path, ';')) != NULL && strncmp (p + 1, "2,", 2) == 0)
#else
if ((p = strchr (h->path, ':')) != NULL && strncmp (p + 1, "2,", 2) == 0)
#endif /* AMIGA */
{
p += 3;
while (*p)
{
switch (*p)
{
case 'F':
h->flagged = 1;
break;
case 'S': /* seen */
h->read = 1;
break;
case 'R': /* replied */
h->replied = 1;
break;
}
p++;
}
}
}
/* set flags and update context info */
mx_update_context (ctx);
}
}
/* Ignore the garbage files. A valid MH message consists of only
* digits. Deleted message get moved to a filename with a comma before
* it.
*/
int mh_valid_message (const char *s)
{
for (; *s ; s++)
{
if (!isdigit (*s))
return 0;
}
return 1;
}
/* Read a MH/maildir style mailbox.
*
* args:
* ctx [IN/OUT] context for this mailbox
* subdir [IN] NULL for MH mailboxes, otherwise the subdir of the
* maildir mailbox to read from
*/
int mh_read_dir (CONTEXT *ctx, const char *subdir)
{
DIR *dirp;
struct dirent *de;
char buf[_POSIX_PATH_MAX];
int isOld = 0;
int count = 0;
struct stat st;
if (subdir)
{
snprintf (buf, sizeof (buf), "%s/%s", ctx->path, subdir);
isOld = (strcmp ("cur", subdir) == 0) && option (OPTMARKOLD);
}
else
strfcpy (buf, ctx->path, sizeof (buf));
if (stat (buf, &st) == -1)
return (-1);
if ((dirp = opendir (buf)) == NULL)
return (-1);
if (!subdir || (subdir && strcmp (subdir, "new") == 0))
ctx->mtime = st.st_mtime;
while ((de = readdir (dirp)) != NULL)
{
if (ctx->magic == M_MH)
{
if (!mh_valid_message (de->d_name))
continue;
}
else if (*de->d_name == '.')
{
/* Skip files that begin with a dot. This currently isn't documented
* anywhere, but it was a suggestion from the author of QMail on the
* mailing list.
*/
continue;
}
mh_parse_message (ctx, subdir, de->d_name, &count, isOld);
}
closedir (dirp);
return 0;
}
/* read a maildir style mailbox */
int maildir_read_dir (CONTEXT *ctx)
{
/* maildir looks sort of like MH, except that there are two subdirectories
* of the main folder path from which to read messages
*/
if (mh_read_dir (ctx, "new") == -1 || mh_read_dir (ctx, "cur") == -1)
return (-1);
return 0;
}
/* Open a new (unique) message in a maildir mailbox. In order to avoid the
* need for locks, the filename is generated in such a way that it is unique,
* even over NFS: <time>.<pid>_<count>.<hostname>. The _<count> part is
* optional, but required for programs like Mutt which do not change PID for
* each message that is created in the mailbox (otherwise you could end up
* creating only a single file per second).
*/
void maildir_create_filename (const char *path, HEADER *hdr, char *msg, char *full)
{
char subdir[_POSIX_PATH_MAX];
char suffix[16];
struct stat sb;
/* the maildir format stores the status flags in the filename */
suffix[0] = 0;
if (hdr && (hdr->flagged || hdr->replied || hdr->read))
{
#ifdef AMIGA
sprintf (suffix, ";2,%s%s%s",
#else
sprintf (suffix, ":2,%s%s%s",
#endif /* AMIGA */
hdr->flagged ? "F" : "",
hdr->replied ? "R" : "",
hdr->read ? "S" : "");
}
if (hdr && (hdr->read || hdr->old))
strfcpy (subdir, "cur", sizeof (subdir));
else
strfcpy (subdir, "new", sizeof (subdir));
FOREVER
{
snprintf (msg, _POSIX_PATH_MAX, "%s/%ld.%d_%d.%s%s",
subdir, time (NULL), getpid (), Counter++, Hostname, suffix);
snprintf (full, _POSIX_PATH_MAX, "%s/%s", path, msg);
if (stat (full, &sb) == -1 && errno == ENOENT) return;
}
}
static int maildir_sync_message (CONTEXT *ctx, int msgno)
{
HEADER *h = ctx->hdrs[msgno];
char newpath[_POSIX_PATH_MAX];
char fullpath[_POSIX_PATH_MAX];
char oldpath[_POSIX_PATH_MAX];
char *p;
/* decide which subdir this message belongs in */
strfcpy (newpath, (h->read || h->old) ? "cur" : "new", sizeof (newpath));
strcat (newpath, "/");
if ((p = strchr (h->path, '/')) == NULL)
{
dprint (1, (debugfile, "maildir_sync_message: %s: unable to find subdir!\n",
h->path));
return (-1);
}
p++;
strcat (newpath, p);
/* kill the previous flags */
#ifdef AMIGA
/* beaware of the dreaded ':' */
if ((p = strchr (newpath, ';')) != NULL) *p = 0;
#else
if ((p = strchr (newpath, ':')) != NULL) *p = 0;
#endif /* AMIGA */
if (h->replied || h->read || h->flagged)
{
#ifdef AMIGA
strcat (newpath, ";2,");
#else
strcat (newpath, ":2,");
#endif /* AMIGA */
if (h->flagged) strcat (newpath, "F");
if (h->replied) strcat (newpath, "R");
if (h->read) strcat (newpath, "S");
}
snprintf (fullpath, sizeof (fullpath), "%s/%s", ctx->path, newpath);
snprintf (oldpath, sizeof (oldpath), "%s/%s", ctx->path, h->path);
if (strcmp (fullpath, oldpath) == 0)
{
/* message hasn't really changed */
return 0;
}
if (rename (oldpath, fullpath) != 0)
{
mutt_perror ("rename");
return (-1);
}
safe_free ((void **)&h->path);
h->path = safe_strdup (newpath);
return (0);
}
/* save changes to a message to disk */
static int mh_sync_message (CONTEXT *ctx, int msgno)
{
HEADER *h = ctx->hdrs[msgno];
FILE *f;
FILE *d;
MESSAGE *msg;
int rc = -1;
char oldpath[_POSIX_PATH_MAX];
char newpath[_POSIX_PATH_MAX];
long loc = 0;
int chflags = CH_